]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
iconGrid: Defer and group animation cleanup
authorDaniel van Vugt <daniel.van.vugt@canonical.com>
Fri, 5 Oct 2018 09:09:22 +0000 (17:09 +0800)
committerFlorian Müllner <florian.muellner@gmail.com>
Tue, 30 Oct 2018 18:01:05 +0000 (18:01 +0000)
The `reactive` property of icon actors was being restored 24 times over
the course of the spring animation, all at slightly different times as
each icon finished animating at different times.

The problem is that toggling `reactive` on an `StWidget` incurs a style
change of the `insensitive` pseudo class, and style changes would quickly
queue relayouts incurring full stage reallocation. This occurred many times
during a spring animation hogging the CPU and limiting the frame rate.

The solution is defer and batch the cleanup for all icons until after the
last icon has finished animating. This way the CPU impact of the style
change and stage relayout isn't felt during the animation so the frame
rate remains higher and smoother. The overall CPU usage of the animation
is also reduced as the remaining relayouts are much more likely to be
grouped into a single frame.

Icon spring animation performance on an i7-7700:
Before: 83% CPU and 47 FPS
After : 78% CPU and 54 FPS
which is about a 22% increase in performance per clock (FPS/CPU).

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/253

js/ui/iconGrid.js

index cbfeb05f4663982a2b3445165554cca78cd97732..5aff027844eedeb81f782c4dc2685ba1fd559a56 100644 (file)
@@ -439,6 +439,11 @@ var IconGrid = new Lang.Class({
     },
 
     _animationDone() {
+        this._clonesAnimating.forEach(clone => {
+            clone.source.reactive = true;
+            clone.source.opacity = 255;
+            clone.destroy();
+        });
         this._clonesAnimating = [];
         this.emit('animation-done');
     },
@@ -559,10 +564,6 @@ var IconGrid = new Lang.Class({
                                    onComplete: () => {
                                        if (isLastItem)
                                            this._animationDone();
-
-                                       actor.opacity = 255;
-                                       actor.reactive = true;
-                                       actorClone.destroy();
                                    }};
                 fadeParams = { time: ANIMATION_FADE_IN_TIME_FOR_ITEM,
                                transition: 'easeInOutQuad',
@@ -583,12 +584,8 @@ var IconGrid = new Lang.Class({
                                    scale_x: scaleX,
                                    scale_y: scaleY,
                                    onComplete: () => {
-                                       if (isLastItem) {
+                                       if (isLastItem)
                                            this._animationDone();
-                                           this._restoreItemsOpacity();
-                                       }
-                                       actor.reactive = true;
-                                       actorClone.destroy();
                                    }};
                 fadeParams = { time: ANIMATION_FADE_IN_TIME_FOR_ITEM,
                                transition: 'easeInOutQuad',
@@ -602,12 +599,6 @@ var IconGrid = new Lang.Class({
         }
     },
 
-    _restoreItemsOpacity() {
-        for (let index = 0; index < this._items.length; index++) {
-            this._items[index].actor.opacity = 255;
-        }
-    },
-
     _getAllocatedChildSizeAndSpacing(child) {
         let [,, natWidth, natHeight] = child.get_preferred_size();
         let width = Math.min(this._getHItemSize(), natWidth);